//
//  String+Extension.swift
//  Library_y
//
//  Created by JC on 2023/6/6.
//

import Foundation
import UIKit
import MobileCoreServices

extension StringProtocol {
    var hexaData: Data { .init(hexa) }
    var hexaBytes: [UInt8] { .init(hexa) }
    private var hexa: UnfoldSequence<UInt8, Index> {
        sequence(state: startIndex) { startIndex in
            guard startIndex < self.endIndex else { return nil }
            let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
            defer { startIndex = endIndex }
            return UInt8(self[startIndex..<endIndex], radix: 16)
        }
    }
}

// MARK: - Properties
public extension String {
    var attributed: NSMutableAttributedString {
        return NSMutableAttributedString(string: self)
    }
    
    // 如果 path中含有中文，则string转url无法成功
    var addingPercentEncoding: String? {
        return self.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    }
    
    // 去转义符
    var deleteControlCharacter: String {
        let ocStr = self as NSString
        let ocMStr = NSMutableString(string: ocStr)
        let set = CharacterSet.controlCharacters
        var range = ocMStr.rangeOfCharacter(from: set)
        while range.location != NSNotFound {
            ocMStr.deleteCharacters(in: range)
            range = ocMStr.rangeOfCharacter(from: set)
        }
        return ocMStr as String
    }
}

public extension String {
    
    /// String 转 Int
    var toInt: Int {
        return Int(self) ?? 0
    }
    
    /// String 转 Double
    var toDouble: Double {
        return Double(self) ?? 0.0
    }
    
    /// String 转 CGFloat
    var toCGFloat: CGFloat {
        return CGFloat(Double(self) ?? 0.0)
    }
    
}

public extension String {
    
    // 字符串String转Int 16
    var int16: Int16? {
        return Int16(self, radix: 16)
    }
    
    /// 字符串的长度
    var length: Int {
        return NSString(string: self).length
    }
    
    /// 获取text的宽度
    ///
    /// - parameter text:   text内容
    /// - parameter font:   text字体的大小
    /// - parameter height: text固定宽度
    ///
    /// - returns: 动态的宽度
    func getWidth(_ font: UIFont, _ height: CGFloat = 17) -> CGFloat {
        let statusLabelText: NSString = self as NSString
        let size = CGSize(width: 900, height: height)
        let dic = NSDictionary(object: font, forKey: NSAttributedString.Key.font as NSCopying)
        let strSize = statusLabelText.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: dic as? [NSAttributedString.Key : AnyObject], context:nil).size
        return strSize.width
    }
    
    /// 获取text的高度
    ///
    /// - parameter text:  text内容
    /// - parameter font:  text字体的大小
    /// - parameter width: text固定宽度
    ///
    /// - returns: 动态的高度
    func getHeight(_ font: UIFont, _ width: CGFloat) -> CGFloat {
        let statusLabelText: NSString = self as NSString
        let size = CGSize(width: width, height: 1000)
        let dic = NSDictionary(object: font, forKey: NSAttributedString.Key.font as NSCopying)
        let strSize = statusLabelText.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: dic as? [NSAttributedString.Key : Any], context: nil).size
        return strSize.height
        
    }
}

public extension String {
    
    var isEmail: Bool {
        let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
        let firstMatch = dataDetector?.firstMatch(in: self, options: .reportCompletion, range: NSRange(location: 0, length: length))
        return (firstMatch?.range.location != NSNotFound && firstMatch?.url?.scheme == "mailto")
    }
    
    var isNum: Bool {
        
        let scan = Scanner(string: self)
        
        var val = Int32(0)
        
        return scan.scanInt32(&val) && scan.isAtEnd
    }
    
    var isPhone: Bool {
        // 首位为 1，11 位
        let phoneRegex = "^1\\d{10}$"
        let phonePredicate = NSPredicate(format: "SELF MATCHES %@", phoneRegex)
        return phonePredicate.evaluate(with: self)
    }
    
    var isMail: Bool {
        
        let mailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let mailPredicate = NSPredicate(format: "SELF MATCHES %@", mailRegex)
        return mailPredicate.evaluate(with: self)
    }
    
    var isCarNo: Bool {
        
        let carNoRegex = "^[\\u4e00-\\u9fa5]{1}[a-zA-Z]{1}[a-zA-Z_0-9]{4}[a-zA-Z_0-9_\\u4e00-\\u9fa5]$"
        let carNoPredicate = NSPredicate(format: "SELF MATCHES %@", carNoRegex)
        return carNoPredicate.evaluate(with: self)
    }
    
    // 和谐手机号中间四位数
    var secureMobile: String {
        if count == 11, isNum {
            let range = NSMakeRange(3, 4)
            return (self as NSString).replacingCharacters(in: range, with: "****")
        } else {
            return ""
        }
    }
}

public extension String {
    // 将一个字符串分割成单个字符数组
    var charactersArray: [Character] { return Array(self) }
     
    var unicodeStr:String {
        let tempStr1 = self.replacingOccurrences(of: "\\u", with: "\\U")
        let tempStr2 = tempStr1.replacingOccurrences(of: "\"", with: "\\\"")
        let tempStr3 = "\"".appending(tempStr2).appending("\"")
        let tempData = tempStr3.data(using: String.Encoding.utf8)
        var returnStr:String = ""
        do {
            returnStr = try PropertyListSerialization.propertyList(from: tempData!, options: [.mutableContainers], format: nil) as! String
        } catch {
            print(error)
        }
        return returnStr.replacingOccurrences(of: "\\r\\n", with: "\n")
    }
}

// 驼峰与下划线之间的转换
public extension String {

    var camelName:String {
        var result = ""
        var flag = false
        self.forEach { c in
            let s = String(c)
            if s == "_" {
                flag = true
            } else {
                if flag {
                    result += s.uppercased()
                    flag = false
                } else {
                    result += s
                }
            }
        }
        return result
    }
    
    var underscore_name:String {
        var result = ""
        self.forEach { c in
            let num = c.unicodeScalars.map { $0.value }.last!
            let s = String(c)
            if num > 64 && num < 91 {
                result += "_"
                result += s.lowercased()
            } else {
                result += s
            }
        }
        return result
    }
    
    enum JsonKeyType {
        case camel, underscore
    }
    
    func convertJsonKeyName(_ keyType: JsonKeyType) -> String {
        let pattern = "[\"' ]*[^:\"' ]*[\"' ]*:"
        var nsStr = self as NSString
        do {
            let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options.caseInsensitive)
            // TODO: - 优化
            var res = regex.matches(in: nsStr as String, options:[NSRegularExpression.MatchingOptions(rawValue: 0)], range: NSMakeRange(0, (nsStr as NSString).length)) // 获取总位置数目
            for i in 0..<res.count {
                // 获取新位置
                res = regex.matches(in: nsStr as String, options:[NSRegularExpression.MatchingOptions(rawValue: 0)], range: NSMakeRange(0, (nsStr as NSString).length)) //str.count
                let c = res[i]
                let cStr = (nsStr as NSString).substring(with: c.range)
                let newStr = keyType == .camel ? cStr.camelName : cStr.underscore_name
                nsStr = nsStr.replacingCharacters(in: c.range, with: newStr) as NSString
            }
            
        } catch {
            print(error)
        }
        return nsStr as String
    }
}

// MARK: - 字符串截取
public extension String {
    /// String使用下标截取字符串
    /// string[index] 例如："abcdefg"[3] // c
    subscript (i:Int)->String{
        let startIndex = self.index(self.startIndex, offsetBy: i)
        let endIndex = self.index(startIndex, offsetBy: 1)
        return String(self[startIndex..<endIndex])
    }
    /// String使用下标截取字符串
    /// string[index..<index] 例如："abcdefg"[3..<4] // d
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
            let endIndex = self.index(self.startIndex, offsetBy: r.upperBound)
            return String(self[startIndex..<endIndex])
        }
    }
    /// String使用下标截取字符串
    /// string[index,length] 例如："abcdefg"[3,2] // de
    subscript (index:Int , length:Int) -> String {
        get {
            let startIndex = self.index(self.startIndex, offsetBy: index)
            let endIndex = self.index(startIndex, offsetBy: length)
            return String(self[startIndex..<endIndex])
        }
    }
    // 截取 从头到i位置
    func substring(to:Int) -> String{
        return self[0..<to]
    }
    // 截取 从i到尾部
    func substring(from:Int) -> String{
        return self[from..<self.count]
    }
}

public extension String {
    
    
    // 从Swift字符串中查找给定子串的所有Range
    func ranges(of string: String) -> [Range<String.Index>] {
        var rangeArray = [Range<String.Index>]()
        var searchedRange: Range<String.Index>
        guard let sr = self.range(of: self) else {
            return rangeArray
        }
        searchedRange = sr
        
        var resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
        while let range = resultRange {
            rangeArray.append(range)
            searchedRange = Range(uncheckedBounds: (range.upperBound, searchedRange.upperBound))
            resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
        }
        return rangeArray
    }

    
    /// range转换为NSRange
    func nsRange(from range: Range<String.Index>) -> NSRange {
        return NSRange(range, in: self)
    }
}

public extension String {
    
    //返回第一次出现的指定子字符串在此字符串中的索引
    //（如果backwards参数设置为true，则返回最后出现的位置）
    func positionOf(sub: String, backwards: Bool = false) -> Int {
        var pos = -1
        if let range = range(of:sub, options: backwards ? .backwards : .literal ) {
            if !range.isEmpty {
                pos = self.distance(from:startIndex, to:range.lowerBound)
            }
        }
        return pos
    }
    
    // 文件后缀
    var file_suffix: String {
        if let index = self.lastIndex(of: ".") {
            return String(self[index...])
        } else {
            return ""
        }
    }
    
    /// 通过 文件路径/文件名/文件后缀 获取mimeType(文件媒体类型)
    /// 需要导入 MobileCoreServices
    var mimeType: String {
        // 通用的二进制类型
        let defaultMIMEType = "application/octet-stream"
        
        // 获取文件名后缀标记
        guard let tag = components(separatedBy: "/").last?
            .components(separatedBy: ".").last?
            .trimmingCharacters(in: .whitespacesAndNewlines) else { return defaultMIMEType }
        
        // 异常则返回 二进制通用类型
        guard let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, tag as CFString, nil)?.takeRetainedValue(),
            let mimeType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue()
            else { return defaultMIMEType }
        
        return mimeType as String
    }
}

public extension String {
    
    /// 是否为空字符串
    var isBlank: Bool {
        // 扔掉 空格和换行符
        let trimmedStr = self.trimmingCharacters(in: .whitespacesAndNewlines)
        return trimmedStr.isEmpty
    }
    
    // 截取tag前面所有的字符串
    func slicePrefix(_ tag: String) -> String {
        guard let range: Range = self.range(of: tag) else { return "" }
        let location: Int = self.distance(from: self.startIndex, to: range.lowerBound)
        let subStr = self.prefix(location)
        return String(subStr)
    }
    
    // 截取tag后面所有的字符串
    func sliceSuffix(_ tag: String) -> String {
        guard let range: Range = self.range(of: tag) else { return "" }
        let location: Int = self.distance(from: self.startIndex, to: range.upperBound)
        let subStr = self.suffix(self.count - location)
        return String(subStr)
    }
    
    // 截取tag前面所有的字符串包括tag
    func slicePrefixContain(_ tag: String) -> String {
        guard let range: Range = self.range(of: tag) else { return "" }
        let location: Int = self.distance(from: self.startIndex, to: range.upperBound)
        let subStr = self.prefix(location)
        return String(subStr)
    }
    
    // 截取tag后面所有的字符串包括tag
    func sliceSuffixContain(_ tag: String) -> String {
        guard let range: Range = self.range(of: tag) else { return "" }
        let location: Int = self.distance(from: self.startIndex, to: range.lowerBound)
        let subStr = self.suffix(self.count - location)
        return String(subStr)
    }
}
